package agriculture.util;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Collections;
import java.util.UUID;

@Component
@RequiredArgsConstructor
public class RedisLockUtil {

    private final StringRedisTemplate redisTemplate;

    // Lua 脚本用于原子性释放锁：只有自己加的锁才能释放
    private static final String UNLOCK_LUA =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                    "   return redis.call('del', KEYS[1]) " +
                    "else return 0 end";

    /**
     * 尝试加锁
     *
     * @param key 锁的 key（例如订单号）
     * @param value 锁的值（一般使用 UUID 保证唯一）
     * @param expireSeconds 锁的过期时间，单位秒，防止死锁
     * @return true 表示获取锁成功，false 表示失败
     */
    public boolean tryLock(String key, String value, long expireSeconds) {
        // 使用 Redis 的 setIfAbsent 命令实现加锁，同时设置过期时间避免死锁
        Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofSeconds(expireSeconds));
        return Boolean.TRUE.equals(success);
    }

    /**
     * 解锁（只有加锁的客户端才能释放锁）
     *
     * @param key 锁的 key（例如订单号）
     * @param value 加锁时存的 value，必须匹配才能释放
     * @return true 表示释放成功，false 表示失败
     */
    public boolean unlock(String key, String value) {
        // 使用 Lua 脚本保证原子性，防止误删他人锁
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(UNLOCK_LUA);
        redisScript.setResultType(Long.class);

        Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
        return result != null && result == 1L;
    }

    /**
     * 生成锁的唯一值，推荐使用 UUID + 线程 ID 或业务 ID
     */
    public static String generateLockValue() {
        return UUID.randomUUID().toString() + "-" + Thread.currentThread().getId();
    }
}
